package wang.conge.javasedemo.core.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * @author conge
 * 2016年7月14日
 */
public class NonBlockingIOClient implements Runnable {

	private String name;
	private String ip;
	private int port;
	
	private int BLOCK = 4096;
	private ByteBuffer sendBuffer = ByteBuffer.allocate(BLOCK);
	private ByteBuffer receiveBuffer = ByteBuffer.allocate(BLOCK);
	
	private AtomicInteger readTimes = new AtomicInteger(2);
	private AtomicBoolean closeFlag = new AtomicBoolean(false);
	
	public NonBlockingIOClient(String index,String ip,int port){
		this.name  = index;
		this.ip = ip;
		this.port = port;
	}
	
	public void run() {
		try {
			deal();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public void deal() throws IOException {
		// 1.open SocketChannel
		SocketChannel socketChannel = SocketChannel.open();
		// 2. configureBlocking false
		socketChannel.configureBlocking(false);
		
		//3 open Selector
		Selector selector = Selector.open();
		//4 socketChannel register selector
		socketChannel.register(selector, SelectionKey.OP_CONNECT);
		 
		//5 socketChannel connect
		socketChannel.connect(new InetSocketAddress(ip, port));
		
		Set<SelectionKey> selectionKeys;
		Iterator<SelectionKey> iterator;
		SelectionKey selectionKey;
		SocketChannel client;
		String receiveText;
		String sendText;
		int count=0;

		while (true) {
			if(closeFlag.compareAndSet(true, false)){
				break;
			}
			//选择一组键，其相应的通道已为 I/O 操作准备就绪。
			//此方法执行处于阻塞模式的选择操作。
			selector.select();
			//返回此选择器的已选择键集。
			selectionKeys = selector.selectedKeys();
			//System.out.println(selectionKeys.size());
			iterator = selectionKeys.iterator();
			while (iterator.hasNext()) {
				selectionKey = iterator.next();
				if (selectionKey.isConnectable()) {
					client = (SocketChannel) selectionKey.channel();
					// 判断此通道上是否正在进行连接操作。
					// 完成套接字通道的连接过程。
					if (client.isConnectionPending()) {
						client.finishConnect();
						String init = "init--" + name;
						System.out.println(init);
						
						sendBuffer.clear();
						sendBuffer.put(init.getBytes());
						sendBuffer.flip();
						client.write(sendBuffer);
					}
					client.register(selector, SelectionKey.OP_READ);
				} else if (selectionKey.isReadable()) {
					client = (SocketChannel) selectionKey.channel();
					//将缓冲区清空以备下次读取
					receiveBuffer.clear();
					//读取服务器发送来的数据到缓冲区中
					count=client.read(receiveBuffer);
					if(count>0){
						receiveText = new String( receiveBuffer.array(),0,count);
						System.out.println(receiveText);
						client.register(selector, SelectionKey.OP_WRITE);
					}
					
					int desc = readTimes.decrementAndGet();
					if(desc  == 0){
						client.close();
						closeFlag.set(true);
						break;
					}
				} else if (selectionKey.isWritable()) {
					sendBuffer.clear();
					client = (SocketChannel) selectionKey.channel();
					sendText = "request--" + name;
					sendBuffer.put(sendText.getBytes());
					 //将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位
					sendBuffer.flip();
					client.write(sendBuffer);
					System.out.println(sendText);
					client.register(selector, SelectionKey.OP_READ);
				}
			}
			selectionKeys.clear();
		}
	}
	
	public static void main(String[] args) {
		String ip = "127.0.0.1";
		int port = 10000;
		
		for(int i=0;i<10;i++){
			String name = "client:"+i;
			
			new Thread(new NonBlockingIOClient(name,ip,port)).start();
		}
		
	}
}
